
#ifndef LOD_SHOW_MESH_DISP_H
#define LOD_SHOW_MESH_DISP_H

#include <string>
#include <vector>
#include <cmath>
#include <fstream>
#include <stdlib.h>
#include <math.h>

#include "disp.h"
#include "../consts.h"
#include "../types.h"
#include "../base/error.h"
#include "../base/vertex.h"
#include "../base/triangle.h"
#include "../base/material.h"
#include "../base/cvertex.h"
#include "../base/vector3.h"
#include "../base/point4.h"
#include "../loader.h"
#include "../object3d.h"
#include "../light/lighting.h"
//#include "../sph_camera.h"
#include "../jeff_camera.h"
#include "../jeff/mesh.h"


#define NO_MAT triangle<it_type,it_type>::NO_MAT

// todo
#include <iostream>
using std::cout;
using std::endl;
using std::flush;
//#include <unistd.h>

class show_mesh_disp : public disp
{
    public:
    show_mesh_disp(void* font, const GLfloat* menu_color4, 
                   const GLfloat* act_menu_color4, int Width, int Height, double Fovy)
     : disp(font, menu_color4, act_menu_color4, show_mesh_disp::text, 
            show_mesh_disp::yinc_text, show_mesh_disp::xoffset_text, 
            show_mesh_disp::show_text, show_mesh_disp::menu_pos,
            show_mesh_disp::text_count,
            show_mesh_disp::help_str, show_mesh_disp::help_count),
       width(Width),
       height(Height),
       typing(false),
       ob(NEG_INF, POS_INF),
       ob_loaded(false),
       display_ob(false),
       use_vbo(false),
       polygon_mode(true),
       //show_disk(true),
       //cam(NULL),
       default_mat(DEFAULT_MAT_DIFF, DEFAULT_MAT_SPEC),
       fovy(Fovy),
       jmesh(NULL),
       ob_type(enum_ob_type::EMPTY)
    {
        //reshape(Width, Height);
        set_act_menu_pos(START_ACT_MENU_POS); 
        //set_show_help(HELP_SHOWED_ON_START); 
        show_help=false;
    }


    virtual ~show_mesh_disp()
    {
        //if(cam!=NULL)
        //    delete cam;
        if(jmesh!=NULL)
            delete jmesh;
    }



    virtual void display(int width, int height)
    {
        if(ob_loaded)
        {
            if(show_help==false) 
            {
                if(display_ob)
                {
                    if(illuminated) {
                        li.enable();
                        default_mat.set();
                    }
                    else {
                        li.disable();
                        grey();
                    }
                    
                    glMatrixMode(GL_MODELVIEW);
                    glLoadIdentity();
                    //cam->place();
                    gluLookAt(0,0,jcam.get_dist(), 0,0,0, 0,1,0);
                    glRotatef(jcam.get_elevation(),1,0,0);
                    glRotatef(jcam.get_azimuth(),0,1,0);
                    
                    //todo I can imagine a better place to do that... 
                    //      but it's at least simple
                    if(polygon_mode)
                        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                    else
                        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

                    //todo
                    /*if(show_disk) {
                        GLCOLOR3(1,1,1);
                        //GLfloat d = (GLfloat)std::sqrt((eye.x-ref_pt.x)*(eye.x-ref_pt.x)+
                        //                                (eye.y-ref_pt.y)*(eye.y-ref_pt.y)+
                        //                                (eye.z-ref_pt.z)*(eye.z-ref_pt.z));
                        int num = 15;
                        for(int i=0; i<num; i++) {
                            GLfloat r = (d/num)*(i+1);
                            int points = 40+i*10;
                            GLfloat step = 2*M_PI/points;
                            GLfloat phi = 0;
                            glBegin(GL_LINE_LOOP);
                            for(int j=0; j<points; j++) {
                                GLVERTEX3(r*std::cos(phi)+ref_pt.x, 
                                        r*std::sin(phi)+ref_pt.y, 
                                        ob.zbord[0]);//0+ref_pt.z);
                                phi += step;
                            }
                            glEnd();
                        }
                    }*/
                    
                    if(ob_type==enum_ob_type::TGT) {
                        glDisable(GL_CULL_FACE); // display_tgt() badly works with culling enabled
                        display_tgt();
                    }
                    else if(ob_type==enum_ob_type::PLY) {
                        glEnable(GL_CULL_FACE); // backface culling
                        display_ply();
                    }
                }//display object==true
                    

                //if(ob_type!=enum_ob_type::EMPTY) { // controlled by ob_loaded variable
                    li.disable();
                    quick_draw_string(width,height,("t: "+get_num_triangles_str()).c_str(),20,60);
                    quick_draw_string(width,height,("v: "+get_num_vertices_str()).c_str(),20,40);
                    quick_draw_string(width,height,("Object: "+ob_name).c_str(),20,20);
                //}
            }//show_help==false
            else if(show_help) {
                li.disable();
                disp_help(width,height);
            }
        }

        // do any time
        li.disable();
        disp_text(width, height);
    }

    virtual disp* keyboard(unsigned char key, int x, int y)
    {
        disp* menu = this;
        if(typing)
        {
            switch(key) {
                //case '\n': 
                //    // in case "\r\n" are generated for enter key
                //    break;
                
                // strange observation: glut gives just '\r' as a newline character
                // under Linux
                case '\r':
                    this->enter_key();
                    break;
                case 27: // escape
                    menu = escape_key();
                    break;
                case '\b':
                    backspace_key();
                    break;
                default:
                    key_typed(key);
            }
        }
        else // typing==false
        {
            switch(key) {
                // strange observation: glut gives just '\r' as a newline character
                // under Linux
                case '\r':
                    this->enter_key();
                    break;
                case 27: // escape
                    menu = escape_key();
                    break;
                case '\b':
                    backspace_key();
                    break;
                    
                case 'l': // turn on or off the lights
                    illuminated = !illuminated;
                    break;
                case 'd': // set display on / display off the loaded object
                    display_ob = !display_ob;
                    break;
                //case 'D': // display the disk's surface
                //    show_disk = !show_disk;
                //    break;
                case 'S':
                    li.swap_shading(); // switch between flat/smooth shading
                    break;
                case 'f':
                    polygon_mode = !polygon_mode;
                    break;

                case 'h':
                    show_help = !show_help;
                    break;
                default:
                    ;
            }
        }
        return menu;
    }

    virtual void reshape(int width, int height)
    {
        if(ob_loaded==false) {
            set_xstart_text(int(width * 1/2.5));
            set_ystart_text(int(height * 1/2.0));
        }
        else {
            set_xstart_text(15);
            set_ystart_text(height-30);
        }
        // store the updated values of width and height
        if(width!=this->width || height!=this->height) {
            this->width = width;
            this->height = height;
            init(); // update the projection matrix
        }
    }

    // todo: intensity of the movement should depend on the position of the camera
    virtual void mouse(int button, int state, int x, int y)
    {
        if(button==GLUT_LEFT_BUTTON) {
            lmb_state = state;
            if(state==GLUT_DOWN)
                rmb_state = GLUT_UP;    // restrict that only one button is pressed
        }
        else if(button==GLUT_RIGHT_BUTTON) {
            rmb_state = state;
            if(state==GLUT_DOWN)
                lmb_state = GLUT_UP;
        }
    }

    virtual void motion(int x, int y)
    {
        jcam.mouseMotion(x,y,width,height, lmb_state==GLUT_DOWN, rmb_state==GLUT_DOWN);
    }

    virtual void passive_motion(int x, int y)
    {
        jcam.mouseMotion(x,y,width,height, false, false);
    }

    virtual void init()
    {
        glViewport(0, 0, (GLsizei) width, (GLsizei) height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(fovy, (GLdouble) width/(GLdouble) height, 
                        0.1, 30.0); // todo should be of dynamic values
        initOpenGL();
    }

    void initOpenGL()
    {
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

        li.disable_all();
        //todo probably it's necessary to bring back the light's parameters
        // (they might have changed in another screen)
	// Enable lights and lighting
	glEnable(GL_LIGHT0); // default value is (1.0, 1.0, 1.0, 1.0)
	glEnable(GL_LIGHTING);

        //todo
	//glEnable(GL_CULL_FACE); // backface culling

        comp_type diff[3] = {0.8, 0.8, 0.8}; // grey
        comp_type spec[3] = {0, 0, 0};
        material<comp_type> m(diff,spec);
        m.shininess=128;
        m.set();

	li.set_smooth_shading(); // Gouraud shading
        //li.set_flat_shading();
    }


    private:
    void enter_key()
    {
        typing = !typing;
        if(typing==true) {
            start_typing();
        }
        else//(typing==false)
        {
            stop_typing();
            
            error e = load_object(typed);
            //todo display a status message at the bottom of the screen
            //for a couple of seconds
            if(e.get_code() == error::OK) 
            {
                std::cout << e.get_desc() << std::endl;
                illuminated = true;
                //show_disk = true;
                display_ob = true;

                reshape(width,height);
            }
            else {
                //std::cout << "In line " << e.get_linenr() << ": ";
                //std::cout << e.get_desc() << std::endl;
                cout<<"ERROR: "<<e.get_desc()<<" (in line: ";
                if(e.get_linenr()!=-1)
                    cout<<e.get_linenr();
                else
                    cout<<"unknown";
                cout<<")"<<endl<<flush;
            }
            //reshape(width,height);
            typed.clear();
        }
    }

    disp* escape_key()
    {
        disp* menu = this;
        if(typing) {
            typing = false;
            typed.clear();
            
            stop_typing();
        }
        else
            menu = change_menu(false); // go back
        return menu;
    }

    void key_typed(unsigned char key)
    {
        //if(typing) {
            typed += key;
            std::string s = std::string(text[1]) + typed;
            change_text(1, s.c_str());
        //}
    }

    void backspace_key()
    {
        if(typing && typed.length()>0) {
            typed = typed.substr(0, typed.length()-1);
            std::string s = std::string(text[1]) + typed;
            change_text(1, s.c_str());
        }
    }

    void start_typing()
    {
        menu_pos_visible(0, false);
        menu_pos_visible(1, true);
        menu_pos_active(0, false);
        menu_pos_active(1, true);
        set_act_menu_pos(1);
    }

    void stop_typing()
    {
        menu_pos_visible(0, true);
        menu_pos_visible(1, false);
        menu_pos_active(0, true);
        menu_pos_active(1, false);
        change_text(1, text[1]);
        set_act_menu_pos(0);
    }

    // capable of loading tgt and ply files
    error load_object(std::string path)
    {
        loader<vertex<co_type>, cvertex<co_type,comp_type>, co_type, comp_type, it_type>  l;
        error e;
        enum_ob_type::type type = enum_ob_type::EMPTY;
        int code;

        if(is_tgt(path)) {
                                            // clear the present object's data 
            e = l.load_tgt(path.c_str(), ob, true);
            type = enum_ob_type::TGT;
        }
        else if(is_ply(path)) {
            e = l.load_ply((char*)path.c_str(), &jmesh, true);
            type = enum_ob_type::PLY;
        }
        else {
            e = error(error::ERROR_unsupported_format);
        }


        code=e.get_code();
        if(code == error::ERROR_couldnot_open_file) 
            ; // it was not possible to open the file (maybe it doesn't exist),
              // but the data of the object wasn't cleared
        else if(code == error::ERROR_ply_failed)
            ;   // like above, we didn't succeed in loading data from the given file,
                // but the existing object was kept
        else if(code == error::ERROR_unsupported_format)
            ;   // the format of the given file in unknown, so we will only inform 
                // the user about it
        else if(code != error::OK) {
            // right... we have two cases here and both relate to tgt file 
            // (ply is handled in other cases every time):
            // 1) the present object is tgt and because the loader works on the same
            // object as we do (to avoid memory overhead), we have to clear it 
            // (since the loader failed)
            if(ob_type==enum_ob_type::TGT) {
                ob.clear();
                ob_loaded = false;
                ob_name.clear();
                ob_type = enum_ob_type::EMPTY;
            }
            // 2) the present object is either ply or we have no object at all
            // (in both cases we leave things as they are, because the ply loader 
            // does not use the same Mesh object as us)
        }
        else // the object loaded okay
        {
            if(type!=ob_type)   // the type of the object has changed, we delete 
            {                   // the previous one, if any
                if(ob_type==enum_ob_type::TGT)
                    ob.clear();
                else if(ob_type==enum_ob_type::PLY) {
                    assert(jmesh!=NULL);
                    delete jmesh;
                    jmesh=NULL;
                }
                //else type==EMPTY
            }

            if(type==enum_ob_type::TGT)
                ob.normalize();
            else if(type==enum_ob_type::PLY)
                jmesh->Normalize();
            else {
                ;
                assert(false);
            }
                
            ob_type=type;
            ob_name = path;
            ob_loaded = true;
            polygon_mode = true; // filled polygons
            show_help = false;
            
            jcam.resetOrientation();
        }
        return e;
    }

    int get_num_triangles()
    {
        int n;
        if(ob_type==enum_ob_type::TGT)
            n=ob.tcount+ob.ctcount;
        else if(ob_type==enum_ob_type::PLY)
            n=jmesh->getNumTriangles();
        
        return n;
    }

    std::string get_num_triangles_str()
    {
        int n=get_num_triangles();
        std::ostringstream os;
        os<<n;
        return os.str();
    }

    int get_num_vertices()
    {
        int n;
        if(ob_type==enum_ob_type::TGT)
            n=ob.vcount+ob.cvcount;
        else if(ob_type==enum_ob_type::PLY)
            n=jmesh->getNumVerts();

        return n;
    }
    
    std::string get_num_vertices_str()
    {
        int n=get_num_vertices();
        std::ostringstream os;
        os<<n;
        return os.str();
    }

    bool is_ply(std::string filename)
    {
        std::ifstream is;
        std::string word;
        bool ret;
        is.open(filename.c_str());
        if(!is)
            return false;

        is>>word;
        if(is && word=="ply")
            ret=true;
        else
            ret=false;
        is.close();
        return ret;
    }

    bool is_tgt(std::string filename)
    {
        std::ifstream is;
        std::string word;
        bool ret;
        is.open(filename.c_str());
        if(!is)
            return false;

        is>>word;
        if(is && word=="vertices")
            ret=true;
        else
            ret=false;
        is.close();
        return ret;
    }

    void display_tgt()
    {
        if(illuminated)
        {
            //li.enable();
            default_mat.set();
            it_type lastm = NO_MAT; 

            
            // non coloured triangles
            glBegin(GL_TRIANGLES);
            for(int i=0; i<ob.tcount; i++)
            {
                if(lastm != ob.tris[i].mat) 
                {
                    // it did not work for me to change a material's 
                    // properties between calls to glBegin() and glEnd()
                    // (some elements supposed to be drawn with shading off 
                    // were actually not drawn) 
                    glEnd();
                    if(ob.tris[i].mat != NO_MAT) {
                        ob.mats[ ob.tris[i].mat ].set();
                        lastm = ob.tris[i].mat;
                    }
                    else {
                        default_mat.set();
                        lastm = NO_MAT;
                    }
                    glBegin(GL_TRIANGLES);
                }
                GLNORMAL3V( &(ob.verts[ ob.tris[i].verts[0] ].normal.x) );
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[0] ].x) );

                GLNORMAL3V( &(ob.verts[ ob.tris[i].verts[1] ].normal.x) );
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[1] ].x) );

                GLNORMAL3V( &(ob.verts[ ob.tris[i].verts[2] ].normal.x) );
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[2] ].x) );

                // flip it
                //GLNORMAL3( -ob.verts[ ob.tris[i].verts[2] ].normal.x,
                //           -ob.verts[ ob.tris[i].verts[2] ].normal.y,
                //           -ob.verts[ ob.tris[i].verts[2] ].normal.z );
                //GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[2] ].x) );
                //GLNORMAL3( -ob.verts[ ob.tris[i].verts[1] ].normal.x,
                //           -ob.verts[ ob.tris[i].verts[1] ].normal.y,
                //           -ob.verts[ ob.tris[i].verts[1] ].normal.z );
                //GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[1] ].x) );
                //GLNORMAL3( -ob.verts[ ob.tris[i].verts[0] ].normal.x,
                //           -ob.verts[ ob.tris[i].verts[0] ].normal.y,
                //           -ob.verts[ ob.tris[i].verts[0] ].normal.z );
                //GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[0] ].x) );
            }
            glEnd();

            //todo vcol (vertex colour paint)

            //default_mat.set();
            //lastm = NO_MAT; 
            //bool vcol = false;
            
            // coloured triangles (i.e. vertex painted)
            glBegin(GL_TRIANGLES);
            for(int i=0; i<ob.ctcount; i++) 
            {
                //assert(ob.ctris[i].mat < ob.mcount);
                if(lastm != ob.ctris[i].mat) {
                    glEnd();
                    //todo vertex paint
                    if(ob.ctris[i].mat != NO_MAT) {
                        //if(ob.mats[ ob.ctris[i].mat ].vcol_paint) {
                         //   ob.mats[ ob.ctris[i].mat ].set_no_diffuse();
                          //  vcol = true;
                        //}
                            
                        //else {
                            ob.mats[ ob.ctris[i].mat ].set();
                            //vcol = false;
                        //}
                        lastm = ob.ctris[i].mat;
                    }
                    else {
                        default_mat.set();
                        lastm = NO_MAT;
                    }
                    glBegin(GL_TRIANGLES);
                }
                /*if(vcol) {
                    GLMATERIALV(GL_FRONT_AND_BACK, GL_DIFFUSE, 
                                ob.cverts[ ob.ctris[i].verts[0] ].col);
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[0] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[0] ].x) );
                    GLMATERIALV(GL_FRONT_AND_BACK, GL_DIFFUSE, 
                                ob.cverts[ ob.ctris[i].verts[1] ].col);
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[1] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[1] ].x) );
                    GLMATERIALV(GL_FRONT_AND_BACK, GL_DIFFUSE, 
                                ob.cverts[ ob.ctris[i].verts[2] ].col);
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[2] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[2] ].x) );
                }*/
                //else {
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[0] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[0] ].x) );
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[1] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[1] ].x) );
                    GLNORMAL3V( &(ob.cverts[ ob.ctris[i].verts[2] ].normal.x) );
                    GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[2] ].x) );

                    // flip the triangle
                    //GLNORMAL3( -ob.cverts[ ob.ctris[i].verts[2] ].normal.x,
                    //           -ob.cverts[ ob.ctris[i].verts[2] ].normal.y,
                    //           -ob.cverts[ ob.ctris[i].verts[2] ].normal.z );
                    //GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[2] ].x) );
                    //GLNORMAL3( -ob.cverts[ ob.ctris[i].verts[1] ].normal.x,
                    //           -ob.cverts[ ob.ctris[i].verts[1] ].normal.y,
                    //           -ob.cverts[ ob.ctris[i].verts[1] ].normal.z );
                    //GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[1] ].x) );
                    //GLNORMAL3( -ob.cverts[ ob.ctris[i].verts[0] ].normal.x,
                    //           -ob.cverts[ ob.ctris[i].verts[0] ].normal.y,
                    //           -ob.cverts[ ob.ctris[i].verts[0] ].normal.z );
                    //GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[0] ].x) );
                //}
            }
            glEnd();
        }//illuminated==false
        else // not illuminated
        {
            GLCOLOR4V(default_mat.diffuse);
            it_type lastm = NO_MAT; 
            // non coloured triangles
            glBegin(GL_TRIANGLES);
            for(int i=0; i<ob.tcount; i++)
            {
                if(lastm != ob.tris[i].mat) {
                    if(ob.tris[i].mat != NO_MAT) {
                        GLCOLOR4V(ob.mats[ ob.tris[i].mat ].diffuse);
                        lastm = ob.tris[i].mat;
                    }
                    else {
                        GLCOLOR4V(default_mat.diffuse);
                        lastm = NO_MAT;
                    }
                }
                // not using lights, so transfer just vertices without normals
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[0] ].x) );
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[1] ].x) );
                GLVERTEX3V( &(ob.verts[ ob.tris[i].verts[2] ].x) );
            }

            
            // coloured triangles
            for(int i=0; i<ob.ctcount; i++) 
            {
                if(lastm != ob.ctris[i].mat) {
                    if(ob.ctris[i].mat != NO_MAT) {
                        GLCOLOR4V(ob.mats[ ob.ctris[i].mat ].diffuse);
                        lastm = ob.ctris[i].mat;
                    }
                    else {
                        GLCOLOR4V(default_mat.diffuse);
                        lastm = NO_MAT;
                    }
                }
                GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[0] ].x) );
                GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[1] ].x) );
                GLVERTEX3V( &(ob.cverts[ ob.ctris[i].verts[2] ].x) );
            }
            glEnd();
        }//illuminated==false
    }

    void display_ply()
    {
        assert(jmesh!=NULL);
        glBegin(GL_TRIANGLES);
        int end=jmesh->getNumTriangles();
        for (int i=0; i<end; i++)
        {
            jeff::triangle t=jmesh->getTri(i);
            float a[3];
             
            if (li.is_smooth_shading())
            {
                    const jeff::vertex& v1 = t.getVert1vertex();
                    const float* pFltV1Norm = v1.getArrayVertNorms();
                    glNormal3fv(pFltV1Norm);
                    const float* pFltArray1 = v1.getArrayVerts();
                    glVertex3fv(pFltArray1);
                    const jeff::vertex& v2 = t.getVert2vertex();
                    const float* pFltV2Norm = v2.getArrayVertNorms();
                    glNormal3fv(pFltV2Norm);
                    const float* pFltArray2 = v2.getArrayVerts();
                    glVertex3fv(pFltArray2);
                    const jeff::vertex& v3 = t.getVert3vertex();
                    const float* pFltV3Norm = v3.getArrayVertNorms();
                    glNormal3fv(pFltV3Norm);
                    const float* pFltArray3 = v3.getArrayVerts();
                    glVertex3fv(pFltArray3);

                    // flip it
                    a[0] = -pFltV3Norm[0];
                    a[1] = -pFltV3Norm[1];
                    a[2] = -pFltV3Norm[2];
                    glNormal3fv(a);
                    glVertex3fv(pFltArray3);
                    a[0] = -pFltV2Norm[0];
                    a[1] = -pFltV2Norm[1];
                    a[2] = -pFltV2Norm[2];
                    glNormal3fv(a);
                    glVertex3fv(pFltArray2);
                    a[0] = -pFltV1Norm[0];
                    a[1] = -pFltV1Norm[1];
                    a[2] = -pFltV1Norm[2];
                    glNormal3fv(a);
                    glVertex3fv(pFltArray1);
            }
            else // flat shaded
            {
                    const float* pFltArrayN = t.getNormal();
                    glNormal3fv(pFltArrayN);
                    const float* pFltArray1 = t.getVert1();
                    glVertex3fv(pFltArray1);
                    const float* pFltArray2 = t.getVert2();
                    glVertex3fv(pFltArray2);
                    const float* pFltArray3 = t.getVert3();
                    glVertex3fv(pFltArray3);

                    a[0] = -pFltArrayN[0];
                    a[1] = -pFltArrayN[1];
                    a[2] = -pFltArrayN[2];
                    glNormal3fv(a);
                    glVertex3fv(pFltArray3);
                    glVertex3fv(pFltArray2);
                    glVertex3fv(pFltArray1);
            }
             
        }
        glEnd();
    }

    void grey()
    {
        // Make everything grey
        glColor3ub(128, 128, 128);
    }




    class enum_ob_type 
    {
        public:
        enum type { EMPTY, TGT, PLY };
    };



    int width;
    int height;

    bool typing;
    std::string typed;
    object3d<vertex<co_type>, cvertex<co_type,comp_type>, co_type, comp_type, it_type>
        ob;
    std::string ob_name;
    bool ob_loaded;

    bool display_ob;
    bool use_vbo;
    bool illuminated;
    bool polygon_mode; // false ~= wireframe, true ~= normal
    //bool show_disk;

    
    //sph_camera* cam;
    jeff_camera jcam;

    lighting li;
    material<comp_type> default_mat;
    int light_id;

    double fovy;

    jeff::Mesh* jmesh;

    enum_ob_type::type ob_type;

    static const char* text[];
    static const int yinc_text[];
    static const int xoffset_text[];
    static bool show_text[];
    static bool menu_pos[];
    static const int text_count;

    static const char* help_str[];
    static const int help_count;

    static const short START_ACT_MENU_POS;
    //static const bool HELP_SHOWED_ON_START;

    static const comp_type DEFAULT_MAT_DIFF[];
    static const comp_type DEFAULT_MAT_SPEC[];
};

#endif // LOD_SHOW_MESH_DISP_H
